from typing import Dict, Any, Optional,List
import json
from redis import Redis
from app.core.config import settings 

class RedisService:
    def __init__(self):
        print("初始化Redis服务")
        self.connected = False
        
        # 尝试连接配置的Redis服务器
        print(f"尝试连接配置的Redis服务器...")
        print(f"Host: {settings.REDIS_HOST}")
        print(f"Port: {settings.REDIS_PORT}")
        print(f"Password: {'*' * len(settings.REDIS_PASSWORD) if settings.REDIS_PASSWORD else 'None'}")
        
        try:
            self.redis = Redis(
                host=settings.REDIS_HOST,
                port=settings.REDIS_PORT,
                password=settings.REDIS_PASSWORD,
                decode_responses=True,
                socket_timeout=5,  # 添加超时设置
                socket_connect_timeout=5  # 连接超时
            )
            # 测试连接
            self.redis.ping()
            print("Redis连接成功")
            self.connected = True
        except Exception as e:
            print(f"配置的Redis连接失败: {str(e)}")
            
            # 尝试连接本地Redis（无密码）
            print("尝试连接本地Redis服务器...")
            try:
                self.redis = Redis(
                    host="localhost",
                    port=6379,
                    decode_responses=True,
                    socket_timeout=5,
                    socket_connect_timeout=5
                )
                self.redis.ping()
                print("本地Redis连接成功")
                self.connected = True
            except Exception as e2:
                print(f"本地Redis连接也失败: {str(e2)}")
                # 仍然创建Redis对象，但后续操作可能会失败
                self.redis = Redis(
                    host=settings.REDIS_HOST,
                    port=settings.REDIS_PORT,
                    password=settings.REDIS_PASSWORD,
                    decode_responses=True
                )
    
    def get_task_key(self, key: str) -> str:
        return f"doi_task:{key}"
    
    def save(self, key: str, status_data: Dict[str, Any]) -> None:
        task_key = self.get_task_key(key)
        #print(f"保存任务状态: {task_id}")
        
        # 准备数据
        data = {
            k: json.dumps(v) if isinstance(v, (dict, list)) else str(v)
            for k, v in status_data.items()
        }
        
        if self.connected:
            try:
                # 保存到Redis
                self.redis.hmset(task_key, data)
                # 设置24小时过期
                self.redis.expire(task_key, 86400)
                #print(f"任务状态保存到Redis成功: {task_id}")
                return
            except Exception as e:
                print(f"保存任务状态到Redis失败: {str(e)}")
 
    def get(self, key: str) -> Optional[Dict[str, Any]]:
        task_key = self.get_task_key(key)
        
        if self.connected:
            try:
                # 从Redis获取数据
                data = self.redis.hgetall(task_key)
                if data:  # 如果Redis中有数据
                    # 处理数据
                    result = {}
                    for k, v in data.items():
                        try:
                            # 尝试解析JSON
                            result[k] = json.loads(v)
                        except (json.JSONDecodeError, TypeError):
                            # 如果不是JSON，保持原样
                            result[k] = v
                    #print(f"从Redis获取任务状态成功: {task_id}")
                    return result
            except Exception as e:
                print(f"从Redis获取任务状态失败: {str(e)}")
        
    def update(self, key: str, updates: Dict[str, Any]) -> None:
        #print(f"更新任务状态: {task_id}")
        try:
            # 获取当前状态
            current_status = self.get(key)
            if current_status:
            # 更新状态
               current_status.update(updates)
            # 保存更新后的状态
               self.save(key, current_status)
            #print(f"任务状态更新成功: {task_id}")
        except Exception as e:
            print(f"更新任务状态失败: {str(e)}")
            # 这里可以添加备用存储方案，如写入本地文件等

    def test_connection(self) -> bool:
        """测试Redis连接是否正常"""
        try:
            self.redis.ping()
            return True
        except Exception as e:
            print(f"Redis连接测试失败: {str(e)}")
            return False

    def get_items_by_pattern(self, pattern: str) -> List[Dict[str, Any]]:
        """获取符合特定模式的所有键及其内容，返回列表"""
        result = []
        
        if self.connected:
            try:
                # 使用scan_iter方法获取所有匹配的键
                for key in self.redis.scan_iter(match=pattern):
                    # 获取每个键的内容
                    data = self.redis.hgetall(key)
                    if data:  # 如果Redis中有数据
                        # 处理数据
                        processed_data = {}
                        for k, v in data.items():
                            try:
                                # 尝试解析JSON
                                processed_data[k] = json.loads(v)
                            except (json.JSONDecodeError, TypeError):
                                # 如果不是JSON，保持原样
                                processed_data[k] = v
                        # 将处理后的数据添加到结果列表中
                        result.append(processed_data)
                return result
            except Exception as e:
                print(f"从Redis获取模式匹配数据失败: {str(e)}")
        
        # Redis连接失败或数据不存在，返回空列表
        return []

    def delete(self, key: str) -> bool:
        """删除任务及其相关数据"""
        task_key = self.get_task_key(key)
    
        # 获取任务信息，提取client_id
        task_info = self.get(key)
        client_id = task_info.get("client_id", "unknown") if task_info else "unknown"
        
        # 删除任务元数据
        success = False
        if self.connected:
            try:
                # 删除Redis中的任务数据
                self.redis.delete(task_key)
                
                # 删除任务相关的DOI项目
                pattern = f"doi_task:doi_item:{key}:*"
                for item_key in self.redis.scan_iter(match=pattern):
                    self.redis.delete(item_key)
                
                print(f"任务删除成功: {key}")
                success = True
            except Exception as e:
                print(f"从Redis删除任务失败: {str(e)}")
        
        # 删除下载文件和源文件
        try:
            import os
            import shutil
            from ..core.config import settings
            
            # 删除任务专用下载目录
            client_dir = os.path.join(settings.DOWNLOAD_DIR, client_id)
            download_dir = os.path.join(client_dir, key)
            if os.path.exists(download_dir) and os.path.isdir(download_dir):
                shutil.rmtree(download_dir)
                print(f"任务下载目录删除成功: {download_dir}")
            
            # 删除ZIP压缩包
            zip_path = os.path.join(client_dir, f"{key}.zip")
            if os.path.exists(zip_path):
                os.remove(zip_path)
                print(f"任务ZIP文件删除成功: {zip_path}")
                
            # 如果client_dir为空，也删除它
            if os.path.exists(client_dir) and os.path.isdir(client_dir) and not os.listdir(client_dir):
                os.rmdir(client_dir)
                print(f"客户端下载目录为空，已删除: {client_dir}")
            
            # 删除源文件目录
            upload_client_dir = os.path.join(settings.UPLOAD_DIR, client_id)
            upload_dir = os.path.join(upload_client_dir, key)
            if os.path.exists(upload_dir) and os.path.isdir(upload_dir):
                shutil.rmtree(upload_dir)
                print(f"任务上传目录删除成功: {upload_dir}")
                
            # 如果upload_client_dir为空，也删除它
            if os.path.exists(upload_client_dir) and os.path.isdir(upload_client_dir) and not os.listdir(upload_client_dir):
                os.rmdir(upload_client_dir)
                print(f"客户端上传目录为空，已删除: {upload_client_dir}")
        except Exception as e:
            print(f"删除任务文件失败: {str(e)}")
            
        return success

    def delete_all_tasks_by_client(self, client_id: str) -> bool:
        """删除指定客户端的所有任务及其相关数据"""
        success = False
        
        if self.connected:
            try:
                # 查找该客户端的所有任务
                pattern = f"doi_task:*"
                all_keys = list(self.redis.scan_iter(match=pattern))
                
                # 筛选出属于该客户端的任务
                client_tasks = []
                for key in all_keys:
                    # 获取任务数据
                    data = self.redis.hgetall(key)
                    # 检查是否属于该客户端
                    if data and data.get('client_id') == client_id:
                        # 提取任务ID
                        task_id = key.split(':')[-1]
                        client_tasks.append(task_id)
                
                # 删除每个任务
                for task_id in client_tasks:
                    self.delete(task_id)
                
                # 删除客户端目录（如果存在）
                try:
                    import os
                    import shutil
                    from ..core.config import settings
                    
                    # 删除下载目录
                    client_dir = os.path.join(settings.DOWNLOAD_DIR, client_id)
                    if os.path.exists(client_dir) and os.path.isdir(client_dir):
                        shutil.rmtree(client_dir)
                        print(f"客户端下载目录删除成功: {client_dir}")
                    
                    # 删除上传目录
                    upload_client_dir = os.path.join(settings.UPLOAD_DIR, client_id)
                    if os.path.exists(upload_client_dir) and os.path.isdir(upload_client_dir):
                        shutil.rmtree(upload_client_dir)
                        print(f"客户端上传目录删除成功: {upload_client_dir}")
                except Exception as e:
                    print(f"删除客户端目录失败: {str(e)}")
                
                print(f"客户端 {client_id} 的所有任务删除成功，共 {len(client_tasks)} 个任务")
                success = True
            except Exception as e:
                print(f"从Redis删除客户端任务失败: {str(e)}")
        
 
        return success

    def get_tasks_by_client_id(self, client_id: str) -> List[Dict[str, Any]]:
        """获取指定客户端的所有任务"""
        result = []
        
        if self.connected:
            try:
                # 查找所有任务
                pattern = f"doi_task:*"
                all_keys = list(self.redis.scan_iter(match=pattern))
                
                # 筛选出属于该客户端的任务
                for key in all_keys:
                    # 获取任务数据
                    data = self.redis.hgetall(key)
                    # 检查是否属于该客户端
                    if data and data.get('client_id') == client_id:
                        # 处理数据
                        processed_data = {}
                        for k, v in data.items():
                            try:
                                # 尝试解析JSON
                                processed_data[k] = json.loads(v)
                            except (json.JSONDecodeError, TypeError):
                                # 如果不是JSON，保持原样
                                processed_data[k] = v
                        # 将处理后的数据添加到结果列表中
                        result.append(processed_data)
                
                #print(f"从Redis获取客户端 {client_id} 的任务成功，共 {len(result)} 个任务")
                return result
            except Exception as e:
                print(f"从Redis获取客户端任务失败: {str(e)}")
        
 
        # 如果都失败，返回空列表
        return []

# 创建全局Redis服务实例
redis_service = RedisService()
# 测试连接并打印结果
connection_status = redis_service.test_connection() 